package com.rambo.baselib.provider;

import ohos.agp.components.BaseItemProvider;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.agp.components.LayoutScatter;
import ohos.agp.render.render3d.ViewHolder;
import ohos.app.Context;

import java.lang.reflect.*;
import java.util.ArrayList;
import java.util.List;

public abstract class ListItemProvider<T, H extends BaseViewHolder> extends BaseItemProvider {
    protected List<T> data;
    protected Context context;
    private int layoutResId;

    public ListItemProvider(Context context, int layoutResId, List<T> data) {
        this.data = data == null ? new ArrayList<>() : data;
        this.context = context;
        this.layoutResId = layoutResId;
    }

    public ListItemProvider(Context context, int layoutResId) {
        this(context, layoutResId, null);
    }

    @Override
    public int getCount() {
        return data.size();
    }

    @Override
    public T getItem(int position) {
        return data.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    public void add(T value) {
        if (value == null) return;
        data.add(value);
        notifyDataSetItemInserted(data.size());
    }

    public void add(List<T> values) {
        if (values == null || values.isEmpty()) return;
        data.addAll(values);
        notifyDataChanged();
    }

    public void replace(List<T> values) {
        data.clear();
        if (values != null && !values.isEmpty()) {
            data.addAll(values);
        }
        notifyDataChanged();
    }

    public void remove(T value) {
        if (value == null) return;
        boolean result = data.remove(value);
        if (result) {
            notifyDataChanged();
        }
    }

    public void remove(int index) {
        if (index < 0 || index >= data.size()) return;
        data.remove(index);
        notifyDataChanged();
    }

    @Override
    public Component getComponent(int position, Component component, ComponentContainer componentContainer) {
        H viewHolder = null;
        if (component == null) {
            viewHolder = createBaseViewHolder(componentContainer);
            component=viewHolder.convertView;
            component.setTag(viewHolder);
        } else {
            viewHolder = (H) component.getTag();
        }
        convert(viewHolder, getItem(position), position);

        return component;
    }

    protected abstract void convert(H helper, T item, int position);

    private H createBaseViewHolder(ComponentContainer parent) {
        Class temp = getClass();
        Class z = null;
        while (z == null && null != temp) {
            z = getInstancedGenericKClass(temp);
            temp = temp.getSuperclass();
        }
        H h;
        // 泛型擦除会导致z为null
        Component view = LayoutScatter.getInstance(context).parse(layoutResId, parent, false);
        if (z == null) {
            h = (H) new BaseViewHolder(view);
        } else {
            h = createGenericKInstance(z, view);
        }
        return h != null ? h : (H) new BaseViewHolder(view);
    }

    /**
     * try to create Generic K instance
     *
     * @param z
     * @param view
     * @return
     */
    @SuppressWarnings("unchecked")
    private H createGenericKInstance(Class z, Component view) {
        try {
            Constructor constructor;
            // inner and unstatic class
            if (z.isMemberClass() && !Modifier.isStatic(z.getModifiers())) {
                constructor = z.getDeclaredConstructor(getClass(), Component.class);
                constructor.setAccessible(true);
                return (H) constructor.newInstance(this, view);
            } else {
                constructor = z.getDeclaredConstructor(Component.class);
                constructor.setAccessible(true);
                return (H) constructor.newInstance(view);
            }
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * get generic parameter K
     *
     * @param z
     * @return
     */
    private Class getInstancedGenericKClass(Class z) {
        Type type = z.getGenericSuperclass();
        if (type instanceof ParameterizedType) {
            Type[] types = ((ParameterizedType) type).getActualTypeArguments();
            for (Type temp : types) {
                if (temp instanceof Class) {
                    Class tempClass = (Class) temp;
                    if (BaseViewHolder.class.isAssignableFrom(tempClass)) {
                        return tempClass;
                    }
                } else if (temp instanceof ParameterizedType) {
                    Type rawType = ((ParameterizedType) temp).getRawType();
                    if (rawType instanceof Class && BaseViewHolder.class.isAssignableFrom((Class<?>) rawType)) {
                        return (Class<?>) rawType;
                    }
                }
            }
        }
        return null;
    }
}
